import { Controller, Get, Param, Query, StreamableFile } from '@nestjs/common';
import { AppService } from './app.service';
import { Config, ExcelExportConfig } from './config';
import errors from './error';
import * as ExcelJS from "exceljs";
import * as path from 'path';
import * as fs from "fs";

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) { }

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  @Get("export/:name")
  async export(@Param("name") name: string, @Query() params: { [key: string]: string }) {
    if (!name) throw errors.argumentNull('name');

    let config = Config.getExportConfig(name);
    this.transformConfig(config, params);

    let data = await this.appService.getDataSource(config);

    let workbook: ExcelJS.Workbook = new ExcelJS.Workbook();
    let sheet: ExcelJS.Worksheet;

    if (config.sourceFile) {
      let sourcePath = path.join(Config.getConfigPath(), config.sourceFile);
      if (!fs.existsSync(sourcePath))
        throw errors.pathNotExists(sourcePath);

      let buffer = fs.readFileSync(sourcePath);
      await workbook.xlsx.load(buffer);
      sheet = workbook.worksheets[0];
      let headerRow = sheet.getRow(1);
      for (let i = 0; i < sheet.actualColumnCount; i++) {
        let cell = headerRow.getCell(i + 1);
        sheet.columns[i].header = cell.text;
      }
    }
    else {
      sheet = workbook.addWorksheet(config.sheetName);
      let columns = Object.keys(config.fields).map(key => ({ dataField: key, title: config.fields[key].title }));
      sheet.columns = columns.map(o => ({ header: o.title }));
    }


    for (let i = 0; i < data.length; i++) {
      let dataItem: any[] = [];
      // let columns = sheet.actualColumnCount;
      for (let j = 0; j < sheet.actualColumnCount; j++) {
        let title = (sheet.columns[j].header as string || '').replaceAll('\n', '').trim();
        let col = config.columns.filter(o => o.title == title)[0];
        let value: any = '';
        if (col) {
          value = data[i][col.dataField];
          if (col.format && value != '') {
            let func = new Function('value', 'index', `return ${col.format}`);
            value = func(value, i);
          }
        }

        dataItem[j] = value;
      }

      sheet.addRow(dataItem);
    }

    let buffer = await workbook.xlsx.writeBuffer();
    return new StreamableFile(buffer as Uint8Array);
  }

  transformConfig(config: ExcelExportConfig, params: { [key: string]: string }) {
    if (!config.dataSource)
      throw errors.memberNull('dataSource', 'config');

    // let ctx = { query: params };
    let query = Object.assign({}, params);
    for (let key in query)
      query[key] = encodeURIComponent(query[key]);

    let func = new Function('query', `return \`${config.dataSource}\`;`);
    config.dataSource = func(query);
  }


}
